package com.agile.leetcode.array.calculate;

/**
 * @Author ChenZhangKun
 * @Date 2020/5/22 14:28
 */

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;


/**
 * 给定一个非空且只包含非负数的整数数组 nums, 数组的度的定义是指数组里任一元素出现频数的最大值。
 * <p>
 * 你的任务是找到与 nums 拥有相同大小的度的最短连续子数组，返回其长度。
 * <p>
 * 示例 1:
 * <p>
 * 输入: [1, 2, 2, 3, 1]
 * 输出: 2
 * 解释:
 * 输入数组的度是2，因为元素1和2的出现频数最大，均为2.
 * 连续子数组里面拥有相同度的有如下所示:
 * [1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
 * 最短连续子数组[2, 2]的长度为2，所以返回2.
 * <p>
 * 示例 2:
 * <p>
 * 输入: [1,2,2,3,1,4,2]
 * 输出: 6
 * <p>
 * 注意:
 * <p>
 * nums.com.agile.leetcode.array.length 在1到50,000区间范围内。
 * nums[i] 是一个在0到49,999范围内的整数。
 */
@SuppressWarnings("all")
public class MinLengthDu {
    public static void main(String[] args) {
        int du = getDu(new Integer[]{1, 2, 2, 3, 1, 5, 5, 6, 4, 5, 6, 4, 5, 6, 5});
        int sub = getSub(new Integer[]{1, 2, 2, 3, 1, 5, 5, 6, 4, 5, 6, 4, 5, 6, 5}, du);
        System.out.println(sub);
    }

    /**
     * 拿到数组的度
     *
     * @param array 原数组
     * @return
     */
    public static int getDu(Integer[] array) {
        // 找出该数组的度
        Map<Integer, Integer> map = new HashMap<>();
        if (array != null) {
            for (int i : array) {
                if (map.containsKey(i)) {
                    map.put(i, map.get(i) + 1);
                } else {
                    map.put(i, 1);
                }
            }
        }
        int max = 0;
        for (Integer integer : map.keySet()) {
            if (map.get(integer) > max) max = map.get(integer);
        }
        return max;
    }

    /**
     * 拿到数组相同度的子数组
     *
     * @param array 原数组
     * @param du    度
     * @return
     */
    public static int getSub(Integer[] array, int du) {
        int length = array.length;
        List<Integer[]> list = new ArrayList<>();
        for (int i = 0; i < length; i++) {
            if (i == length - 1) {
                list.add(new Integer[]{array[length - 1]});
                continue;
            }
            list.add(new Integer[]{array[i]});
            if (i == 0) {
                for (int j = i + 1; j < length; j++) {
                    Integer[] integers = new Integer[j + 1];
                    for (int m = i; m < j + 1; m++) {
                        integers[m] = array[m];
                    }
                    list.add(integers);
                }
            } else if (i == 1) {
                for (int j = i + 1; j < length; j++) {
                    Integer[] integers = new Integer[j];
                    int n = 0;
                    for (int m = i; m < j + 1; m++) {
                        integers[n] = array[m];
                        n++;
                    }
                    list.add(integers);
                }
            } else {
                int k = 2;
                for (int j = i + 1; j < length; j++) {
                    Integer[] integers = new Integer[k];
                    int n = 0;
                    for (int m = i; m < j + 1; m++) {
                        integers[n] = array[m];
                        n++;
                    }
                    list.add(integers);
                    k++;
                }
            }
        }
        // 消除度不一样的
        Predicate<Integer[]> p = o1 -> {
            if (getDu(o1) != du) {
                return false;
            }
            return true;
        };
        List<Integer[]> collect = list.stream().filter(p).collect(Collectors.toList());
        // 拿到度相同的最小数组
        int min = length + 1;
        for (Integer[] integers : collect) {
            if (integers.length < min) min = integers.length;
        }
        return min;
    }
}

// leetcode官方解法
class Solution {
    public int findShortestSubArray(int[] nums) {
        // 创建三个hashmap
        // left 存储第一次出现的索引
        // right 存储最后一次出现的索引
        // count 每个元素出现的次数
        Map<Integer, Integer> left = new HashMap(),
                right = new HashMap(), count = new HashMap();

        for (int i = 0; i < nums.length; i++) {
            int x = nums[i];
            if (left.get(x) == null) left.put(x, i);
            right.put(x, i);
            count.put(x, count.getOrDefault(x, 0) + 1);
        }
        // 数组长度
        int ans = nums.length;
        // 数组的度
        int degree = Collections.max(count.values());
        // 获取相同度最小长度的数组
        for (int x : count.keySet()) {
            if (count.get(x) == degree) {
                ans = Math.min(ans, right.get(x) - left.get(x) + 1);
            }
        }
        return ans;
    }

    public static void main(String[] args) {
        int shortestSubArray = new Solution().findShortestSubArray(new int[]{1, 2, 2, 3, 1, 4, 2});
        System.out.println(shortestSubArray);
    }
}


